from typing import Optional

from fastapi import Depends
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from starlette.requests import Request
from tortoise import Model
from tortoise.contrib.pydantic import PydanticModel
from tortoise.expressions import Q

from core.security import verify_password
from models import User
from scheams import FailureResponse, SuccessResponse
from scheams.login import LoginByIP
from scheams.user import UserLogin_Pydantic, User_Pydantic
from utils import jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v1/login")


async def login(login_model: Model, login_pydantic: UserLogin_Pydantic,
                login_form: OAuth2PasswordRequestForm = Depends(), ):
    data = login_pydantic.from_orm(await login_model.filter(username=login_form.username).first())
    if data and verify_password(login_form.password, data.password):
        token = jwt.create_token(username=data.username, role=data.role)
        # return SuccessResponse(data={"token": token, "token_type": "bearer"}, message="登陆成功")
        return {"access_token": token, "token_type": "bearer"}
    else:
        return FailureResponse(message="登陆失败，请检查您的输入", code=400)


async def login_by_ip(login_model: Model, login_form: LoginByIP, login_pydantic: PydanticModel):
    data = login_pydantic.from_orm(await login_model.filter(ip=login_form.ip).first())
    if data:
        token = jwt.create_token(username=data.ip, role="")
        return SuccessResponse(data={"token": token}, message="登陆成功")
    else:
        return FailureResponse(message="登陆失败，请检查您的输入", code=400)


async def get_user_by_username(login_model: Model, username: str, user_pydantic: PydanticModel):
    data = await login_model.filter(Q(username=username)).first()
    if data:
        return SuccessResponse(message="登陆成功", data=user_pydantic.from_orm(data))
    else:
        return FailureResponse(message="登陆失败，请检查您的输入", code=400)


async def get_current_user(token: str = Depends(oauth2_scheme)):
    payload, msg = jwt.validate_token(token)
    if payload is None:
        return FailureResponse(message="验证失败", code=400)
    return await get_user_by_username(User, payload["username"], User_Pydantic)
